/*
 *  Copyright (C) 2010 Zubanov Dmitry
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


/**
 *
 * @author Zubanov Dmitry aka javadimon, zubanov@gmail.com
 * Omsk, Russia, created 29.05.2010
 * (C) Copyright by Zubanov Dmitry
 */

package org.jssdb.core.josql;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.select.Limit;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import org.jssdb.core.utils.JSQLExeption;

public class OQLParser {

    private CCJSqlParserManager parserManager;
    private static OQLParser self = null;
    private static final Logger logger = Logger.getLogger(OQLParser.class.getName());

    private OQLParser() {
        //parserManager = new CCJSqlParserManager();
    }

    public static OQLParser getInstance() {
        if (self == null) {
            self = new OQLParser();
        }

        return self;
    }

    public Map<String, Object> getParameters(String request) throws JSQLExeption {
        parserManager = new CCJSqlParserManager();
        Map<String, Object> map = new LinkedHashMap();
        net.sf.jsqlparser.statement.Statement statement = null;
        try {
            statement = parserManager.parse(new StringReader(request));
        } catch (JSQLParserException ex) {
            logger.log(Level.SEVERE, request, ex);
        }

        // parse SELECT
        ArrayList<Map<String, String>> aSelect = new ArrayList();
        Select select = (Select) statement;
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
        for (int i = 0; i < plainSelect.getSelectItems().size(); i++) {
            // Map key is alias, value is class
            Map<String, String> mapSelect = new LinkedHashMap();
            SelectExpressionItem selItem = (SelectExpressionItem) plainSelect.getSelectItems().get(i);
            if (selItem.getAlias() == null) {
                mapSelect.put("" + selItem.getExpression(), "" + selItem.getExpression());
            } else {
                mapSelect.put("" + selItem.getAlias(), "" + selItem.getExpression());
            }
            aSelect.add(mapSelect);
        }
        map.put("select", aSelect);

        // parse FROM
        map.put("from", plainSelect.getFromItem());

        // parse ORDER
        Map mOrderBy = new HashMap();
        if (plainSelect.getOrderByElements() != null) {
            mOrderBy.put("class", "" + plainSelect.getOrderByElements().get(0));
            mOrderBy.put("isASC", ((OrderByElement) plainSelect.getOrderByElements().get(0)).isAsc());
        }
        map.put("order", mOrderBy);

        // parse LIMIT
        Map mLimit = new HashMap();
        Limit limit = plainSelect.getLimit();
        if (limit != null) {
            mLimit.put("offset", limit.getOffset());
            mLimit.put("count", limit.getRowCount());
        }
        map.put("limit", mLimit);

        Expression e = plainSelect.getWhere();
        map.put("where", e);

        return map;
    }
}
